<?php
/**
 * MAF
 **
 * File:
**/

/**
 * Class: MAF: E: Exception
 **
 * @package MAF
 * @subpackage Core
**/
class maf__e__exception
	extends exception
	implements ArrayAccess, iteratorAggregate, countable {

	protected $attachments = array();
	protected $tags        = array();

	protected $id;
	protected $call;
	protected $verbose = FALSE;

	public function __toString() {

		try {

			$return = sprintf(
				"Exception: %s #%s {%s\n%s%s%s%s%s%s\n%s\n\n} #%s\n",
				get_class($this),
				$this->getID(),
				$this->getTemplatedMessage(),
				$this->getTemplatedCall(),
				$this->getTemplatedCode(),
				$this->getTemplatedFile(),
				$this->getTemplatedFileSource(),
				$this->getTemplatedTags(),
				$this->getTemplatedAttachments(),
				$this->getTemplatedTrace(),
				$this->getID()
			);

			return ( PHP_SAPI === "cli" ) ? $return : htmlentities($return, ENT_QUOTES);

		} catch ( exception $e ) {

			echo $e->__toString();

		}	# try

	}	# Function

	public function display() {

		if( is_callable( array("maf__e2e", "catcherException") ) ) {

			maf__e2e::catcherException($this);

		} else {

			echo $this->__toString();

		}	# if

	}	# Function

	public function replaceMessage($_) {

		$this->message = (string) $_;

	}	# Function

	protected function setMessage($_) {

		$this->message = (string) $_;

	}	# Function

	protected function setCode($_) {

		$this->code = (integer) $_;

	}	# Function

	protected function setLine($_) {

		$this->line = (integer) $_;

	}	# Function

	protected function setFile($_) {

		$this->file = (string) $_;

	}	# Function

	public function getVerbose() {

		return $this->verbose;

	}	# Function

	public function setVerbose($_) {

		$this->verbose = (bool) $_;

	}	# Function

	/**
	 * @return arrayObject
	**/
	public function getIterator() {

		return new arrayObject($this->attachments);

	}	# Function

	public function getID() {

		return isset_or_set($this->id, strtoupper( sprintf("%08x", crc32( get_class($this) ) ) ) );

	}	# Function

	protected function getAttachment($_) {

		return isset_or($this->attachments[$_]);

	}	# Function

	protected function getAttachments() {

		return (array) $this->attachments;

	}	# Function

	protected function getCode__asString() {

		static $codes = array(
			E_ERROR           => "PHP Error",
			4096              => "PHP Error",
			E_WARNING         => "PHP Warning",
			E_NOTICE          => "PHP Notice",
			E_PARSE           => "Parsing Error",
			E_CORE_ERROR      => "Core Error",
			E_CORE_WARNING    => "Core Warning",
			E_COMPILE_ERROR   => "Compile Error",
			E_COMPILE_WARNING => "Compile Warning",
			E_USER_ERROR      => "User Error",
			E_USER_WARNING    => "User Warning",
			E_USER_NOTICE     => "User Notice",
			E_STRICT          => "Runtime Strict Notice"
		);

		return (string) isset_or($codes[$this->getCode()], $this->getCode());

	}	# Function

	protected function getCall() {

		if( !$this->call ) {

			$trace = $this->getTrace();
			$trace = isset_or($trace[0], array());

			$this->call = sprintf(
				"%s%s%s()",
				isset_or($trace["class"], ""),
				isset_or($trace["type"],  ""),
				isset_or($trace["function"], "{main}")
			);

		}	# if

		return $this->call;

	}	# Function

	public function offsetExists($_) {

		return isset($this->attachments[$_]);

	}	# Function

	public function offsetGet($_) {

		return isset_or($this->attachments[$_]);

	}	# Function

	public function offsetSet($_key_ = NULL, $_value_) {

		switch($_key_) {

		case NULL:
			$this->attachments[] = $_value_;
			break;

		default:
			$this->attachments[$_key_] = $_value_;
			break;

		}	# switch

	}	# Function

	public function offsetUnset($_) {

		unset($this->attachments[$_]);

	}	# Function

	public function count() {

		return count($this->attachments);

	}	# Function

	public function setTag($_tag_) {

		if( !in_array((string) $_tag_, $this->tags, TRUE)) {
			$this->tags[] = (string) $_tag_; }

	}	# Function

	public function getTags() {

		return (array) $this->tags;

	}	# Function

	public function hasTag($_tag_) {

		return in_array((string) $_tag_, $this->tags, TRUE);

	}	# Function

	protected function getTemplatedMessage() {

		return sprintf("\n\nMessage: {\n%s\n}", $this->getMessage());

	}	# Function

	protected function getTemplatedCall() {

		return sprintf("\nCall: %s", $this->getCall());

	}	# Function

	protected function getTemplatedCode() {

		return sprintf("\nCode: %s (%s)", $this->getCode__asString(), $this->getCode());

	}	# Function

	protected function getTemplatedFile() {

		return sprintf("\nFile: %s:%s", $this->getFile(), $this->getLine());

	}	# Function

	protected function getTemplatedFileSource() {

		if( !is_file( $this->getFile() ) || !is_readable( $this->getFile() ) ) {
			return ""; }

		$source       = fopen($this->getFile(), "r");
		$current_line = 1;
		$return       = "";

		while( !feof($source) ) {

			$line = fgets($source);

			if( $current_line > ($this->getLine() - 4) && $current_line < ($this->getLine() + 4) ) {
				$return .= sprintf("%s: %s", $current_line, $line); }

			$current_line++;

		}	# while

		return sprintf("\nFile source: {\n%s}", $return);

	}	# Function

	protected function getTemplatedTags() {

		if( !count( $this->getTags() ) ) {
			return ""; }

		return sprintf("\nTags: %s", implode(", ", $this->getTags()));

	}	# Function

	protected function getTemplatedAttachments() {

		if( !count( $this->getAttachments() ) ) {
			return ""; }

		$return = "";

		foreach($this->getAttachments() as $_key => $_attachment) {

			if( is_object($_attachment) && method_exists($_attachment, "__toString") ) {
				$_attachment =  $_attachment->__toString(); }

			$return .= sprintf("\n\nAttachment: #%s {\n%s\n}", $_key, print_r($_attachment, TRUE));

		}	# foreach

		return $return;

	}	# Function

	protected function getTemplatedTrace() {

		$return = "\nTrace: {\n";

		if( $this->verbose ) {

			foreach( $this->getTrace() as $_key => $_trace ) {
				$return .= $this->getTemplatedTraceRecord($_trace, $_key); }

			$return .= $this->getTemplatedTraceRecord( array(), (isset_or($_key, 0)+1) );

		} else {

			$return .= $this->getTraceAsString();

		}	# if

		$return .= "\n}";

		return $return;

	}	# Function

	protected function getTemplatedTraceRecord(array $_trace_, $_key_) {

		return sprintf(
			"%s%s%s%s\n",
			sprintf("\n=> #%s", $_key_),
			sprintf(
				"\nCall: %s%s%s()",
				isset_or($_trace_["class"],""),
				isset_or($_trace_["type"],""),
				isset_or($_trace_["function"], "{main}")
			),
			isset($_trace_["file"]) ?
				sprintf("\nFile: %s:%s", isset_or($_trace_["file"]), isset_or($_trace_["line"], "0")) :
				"",
			sprintf("\n\nArgs: {\n%s}", print_r( isset_or($_trace_["args"], array()), TRUE))
		);

	}	# Function

}	# Class

/* EOF */